package stool.juc.ticket;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 卖票
 * 线程操作资源类
 * （1）synchronized是独占锁，加锁和解锁的过程自动进行，易于操作，但不够灵活。ReentrantLock也是独占锁，加锁和解锁的过程需要手动进行，不易操作，但非常灵活。
 * （2）synchronized可重入，因为加锁和解锁自动进行，不必担心最后是否释放锁；ReentrantLock也可重入，但加锁和解锁需要手动进行，且次数需一样，否则其他线程无法获得锁。
 * （3）synchronized不可响应中断，一个线程获取不到锁就一直等着；ReentrantLock可以响应中断。
 * ReentrantLock好像比synchronized关键字没好太多，我们再去看看synchronized所没有的，一个最主要的就是ReentrantLock还可以实现公平锁机制。什么叫公平锁呢？也就是在锁上等待时间最长的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。
 * @author Felix YF Dong
 * @Description
 * @Date 2023/2/17
 */
public class TicketSale {

    public static void main(String[] args) {
        Ticket  ticket = new Ticket();
        new Thread(()->{for (int i = 0; i <40 ; i++) ticket.saleTicket();},"A").start();
        new Thread(()->{for (int i = 0; i <40 ; i++) ticket.saleTicket();},"B").start();
        new Thread(()->{for (int i = 0; i <40 ; i++) ticket.saleTicket();},"C").start();
    }
}

class TicketOld {
    private int number = 30;
    public synchronized void  saleTicket(){
        if (number > 0){
            System.out.println(Thread.currentThread().getName() + "卖出第" + number-- + "张票，还剩" + number);
        }
    }
}

class Ticket{
    private int number=30;
    // 可重入锁
    private Lock lock=new ReentrantLock();
    public  void  saleTicket(){

        // 上锁
        lock.lock();
        try {
            if (number > 0){
                System.out.println(Thread.currentThread().getName() + "卖出第" + number-- + "张票，还剩" + number);
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            //释放锁
            lock.unlock();
        }

    }
}
